package nio;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 
 * Buffer对象
 * Buffer都是采用链式编程的方式
 *  mark = -1(标记地址);
 *  position = 0(指这个buffer数据所在的位置);
 *  limit(限制);
 *  capacity(容器大小);
 *	0<=mark<=position<=limit<=capacity
 *
 * capacity 作为一个内存块，Buffer有一个固定的大小值，也叫“capacity”.
 * 你只能往里写capacity个byte、long，char等类型。一旦Buffer满了， 需要将其清空（通过读数据或者清除数据）才能继续写数据往里写数据。
 * 
 * position 当你写数据到Buffer中时，position表示当前的位置。
 * 初始的position值为0.当一个byte、long等数据写到Buffer后，
 * position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.
 * 当读取数据时，也是从某个特定位置读。当将Buffer从写模式切换到读模式，position会被重置为0.
 * 当从Buffer的position处读取数据时，position向前移动到下一个可读的位置。
 * 
 * limit 在写模式下，Buffer的limit表示你最多能往Buffer里写多少数据。
 * 写模式下，limit等于Buffer的capacity。当切换Buffer到读模式时，
 * limit表示你最多能读到多少数据。因此，当切换Buffer到读模式时， limit会被设置成写模式下的position值。换句话说，
 * 你能读到之前写入的所有数据（limit被设置成已写数据的数量，这个值在写模式下就是position）
 */
public class Buffer {

	public static void main(String[] args) throws IOException {
		t3();
		/*
		 * //要想获得一个Buffer对象首先要进行分配。 每一个Buffer类都有一个allocate方法。下
		 * //面是一个分配48字节capacity的ByteBuffer的例子。 ByteBuffer
		 * bb=ByteBuffer.allocate(64); //这是分配一个可存储1024个字符的CharBuffer： CharBuffer
		 * buf = CharBuffer.allocate(1024);
		 * //如果Buffer中仍有未读的数据，且后续还需要这些数据，但是此时想要先先写些数据，那么使用compact()方法。
		 * 
		 * //把buffer清空,好用于下一次读取数据，没有读取的也清空 bb.clear(); 
		 * //把读取到的清空,没有读取的放在开头处
		 * bb.compact(); //通过调用Buffer.mark()方法，可以标记Buffer中的一个特定position。
		 * //之后可以通过调用Buffer.reset()方法恢复到这个position
		 */
	}

	public static void t1() throws IOException {
		FileInputStream fis = new FileInputStream(new File(
				"D:\\good\\good\\src\\test\\java\\nio\\Buffer.java"));
		FileChannel fc = fis.getChannel();
		ByteBuffer buf = ByteBuffer.allocate(8);
		Integer it = fc.read(buf);
		while (it != -1) {
			buf.flip();
			while (buf.hasRemaining()) {
				System.out.println((char) buf.get());
			}
			buf.clear();
			it = fc.read(buf);
		}
		fc.close();
		fis.close();
	}

	public static void t2() throws CharacterCodingException {
		// Charset charset = Charset.forName("UTF-8");
		Charset charset = StandardCharsets.UTF_8; // 注意:StandardCharsets是jdk1.7添加的

		// 从字符集中创建相应的编码和解码器
		CharsetEncoder encoder = charset.newEncoder();
		CharsetDecoder decoder = charset.newDecoder();

		// 构造一个buffer
		CharBuffer charBuffer = CharBuffer.allocate(64);
		//清空缓存
		charBuffer.clear();
		//添加
		charBuffer.put('好');
		charBuffer.put('好');
		charBuffer.put('学');
		charBuffer.put('习');
		charBuffer.put(',');
		charBuffer.put('天');
		charBuffer.put('天');
		charBuffer.put('向');
		charBuffer.put('上');
		charBuffer.put('!');
		System.out.println(charBuffer.position());
		//切换读
		charBuffer.flip();
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.position());

		// 将字符序列转换成字节序列
		ByteBuffer bb = encoder.encode(charBuffer);
		for (; bb.hasRemaining();) {
			//获取
			System.out.print(bb.get() + " ");
		}

		// 将字节序列转换成字符序列
		bb.flip();
		CharBuffer cb = decoder.decode(bb);
		System.out.println("\n" + cb);
	}
	public static void t3(){
		char[] chars="I'm is 杰".toCharArray();
		System.out.println(chars);
		//保存的是chars的引用,改变chars和charBuffer都会改变chars的最终结果
		CharBuffer charBuffer=CharBuffer.wrap(chars, 0, chars.length);
		charBuffer.put(0, 'A');
		charBuffer.flip();
		//复制一个相同的缓存区,共享所有的东西
		charBuffer.duplicate();
		//复制一个相同的缓存区,但只是reaOnly的
		charBuffer.asReadOnlyBuffer();
		if(charBuffer.hasArray()){
			System.out.println(charBuffer.array());
		}
	}

}
